<?php

require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Lz.php';


/**
 *  Base class for POD (Plain Old Data) classes.
 *
 *  @author     GoniX aka Giedrius Dubinskas
 *  @created    2007-02-08
 *  @changed    2007-05-13
 *      + Some methods
 *  @changed    2007-10-24
 *      * Adopted for Lazap
 *  @changed    2008-01-03
 *      + Added tests
 *      * Impoved prototype() performace
 *      * Fixed assign()
 */
abstract class LzPod
{
    protected
    function __construct($data = NULL)
    {
        $this->attach($data);
    }


    public
    function __toString()
    {
        return (string)$this->data;
    }


    public
    function __clone()
    {
        $this->assign($this->data);
    }


     /**
     *  Returns copy of object.
     *
     *  Same as @c clone. Desined for chained calls.
     *
     *  @return [this] @c $this copy.
     */
    public
    function copy()
    {
        return clone $this;
    }


    /**
     *  Creates object prototype.
     *
     *  Note:
     *      Don't do this:      $var = $obj->prototype($var);
     *      When you do this you get $obj internal data set to $obj it self.
     *      This happens because:
     *          1. LzPod::prototype() takes $var reference and attaches new
     *              object internal data to it.
     *          2. Object returned by LzPod::prototype() is assigned to
     *              $var
     *          3. Object's internal data which was attached to the $var
     *              in the first step now is attached to the object it self
     *              (*RECURSION*).
     *
     *      Do this instead:    $var = $obj->prototype()->assign($var);
     *      Now the object internal data is assigned to the copy of $var
     *      and then $var is is assigned to new object. Everyones happy :-)
     *
     *  @param  $data   [mixed] Data to attach to prototyped object.
     *  @return [this]  Object prototype.
     */
    protected
    function prototype(&$data = NULL)
    {
        // this one is really slow when $this->data is big
        //return $this->copy()->attach($data);

        $temp       = &$this->data;

        $null       = NULL;
        $this->data = &$null;
        $prot       = $this->copy()->attach($data);

        $this->data = &$temp;

        return $prot;
    }


    /**
     *  Attaches object to specified data.
     *
     *  @return [this]
     */
    protected
    function attach(&$data)
    {
        $this->data = &$data;
        return $this;
    }


    /**
     *  Sets object to specified data.
     *
     *  @return [this]
     */
    protected
    function assign($data)
    {
        $copy   = Lz::copy($data);
        return $this->attach($copy);
    }


    /**
     *  Returns copy of internal data.
     */
    protected
    function data()
    {
        return $this->data;
    }


    protected $data;
}

